/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_SHAPEDATA_H
#define M_SHAPEDATA_H

#include "physictools.h"
#include "entity.h"
#include "refptr.h"
#include "signal.h"

namespace Engine
{

	/**
	*   The types of Shapes.
	*/
	enum ShapeType
	{
		ST_BOX,
		ST_SPHERE,
		ST_MESH
	};

	/**
	*   A data structure describing a Shape
	*/
	class ShapeData
	{
	public:

		ShapeData(ShapeType t)
			:type(t)
			,position(Matrix4<REAL>::IDENTITY)
			,CollisionSignal(new Signal<EntityPtr, Vector3<REAL>, Vector3<REAL>, REAL>)
			,collisionDepth(0)
		{}

		virtual ~ShapeData(){}

		virtual ShapeData* Clone()const = 0;

		ShapeType type;
		RefPtr<PhysicMaterial, WeakPtrExtension> material;
		Matrix4<REAL> position;
		EntityPtr entity;
		RefPtr<Signal<EntityPtr, Vector3<REAL>, Vector3<REAL>, REAL> > CollisionSignal;
		REAL collisionDepth; ///< Physic system test real collison depth with this value for emiting collision signal.
	};

	/**
	*   A data structure describing a Box shape
	*/
	class BoxShapeData: public ShapeData
	{
	public:
		BoxShapeData()
			:ShapeData(ST_BOX)
			,size(Vector3<REAL>::ZERO)
		{}

		Vector3<REAL> size;

		virtual ShapeData* Clone()const;
	};

	/**
	*   A data structure describing a Sphere shape
	*/
	class SphereShapeData: public ShapeData
	{
	public:
		SphereShapeData()
			:ShapeData(ST_SPHERE)
			,radius(0)
		{}

		REAL radius;

		virtual ShapeData* Clone()const;
	};

	/**
	*   Mesh data.
	*/
	struct MeshData
	{
		MeshData()
			:vertexStride(sizeof(Vector3<float>))
			,triStride(sizeof(unsigned int) * 3){}

		std::vector<Vector3<float> > vertices;
		std::vector<unsigned int> indices;
		unsigned int vertexStride;
		unsigned int triStride;
	};
	typedef RefPtr<MeshData> MeshDataPtr;


	/**
	*   A data structure describing a Mesh shape
	*/
	class MeshShapeData: public ShapeData
	{
	public:
		typedef std::map<std::string, MeshDataPtr> MeshDataMap;

		MeshShapeData()
			:ShapeData(ST_MESH)
			,m_builded(false)
		{}

		~MeshShapeData();

		void Build();
		virtual ShapeData* Clone()const;

		MeshDataPtr data;

	private:

		static MeshDataPtr GetMeshData(const std::string& name);
		static void Save(const std::string& name, MeshDataPtr d);
		static void Delete(const std::string& name);

		static MeshDataMap m_datas;
		bool m_builded;
	};
}

#endif
